生JSのReactプロジェクトにTypeScriptを導入してみた【Zendeskアプリ開発環境】
こんにちは、ゲームソリューショングループの入井です。
今回の記事では、TypeScriptを追加導入して型安全な状態でZendeskのアプリ開発を行えるようにする手順をご紹介します。
生JSで複雑なアプリを書くのはつらい
Zendeskアプリ開発では、アプリのビルドやテスト・デプロイを行うためにZCLIというコマンドラインツールを使用します。
ZCLIでは、以下のコマンドを使用することでZendeskアプリ開発用のコード・設定ファイルが揃ったReactのプロジェクト環境を自動的にセットアップできます。
zcli apps:new --scaffold=react
しかし、セットアップされるReactプロジェクトはTypeScriptに対応しておらず、いわゆる生JSで書くことが前提になっています。
型安全性の無い生JSでの開発は、コードの記述や環境構築が簡潔に済ませられるメリットはあります。しかし、開発対象のアプリがある程度の規模や複雑さを超えると、型チェック漏れによる実行時エラーやバグが頻発したり、エディタのサポートツールの機能が十分に使用できなかったり、コードが読みづらくなり保守性が低下する等、開発が途端に大変になってしまいます。
設定手順
生JSで生成されたプロジェクトであっても、専用のパッケージをインストールして設定を調整することで、TypeScript環境に移行することが可能です。
ここからは、TypeScriptを導入するための手順を記載していきます。
プロジェクトの初期状態の確認
最初に、ZCLIでセットアップされたプロジェクトの初期状態を見ていきます。
JSに関係する部分では、以下のようにディレクトリやファイルが生成されています。
├── lib │ ├── helpers.js │ ├── i18n.js ├── locations │ └── ticket_sidebar.js └── modules ├── app.js └── event_timeline.js
上記のように、生成されたソースファイルはすべて.jsであり.tsのものはありません。当然、npmでもTypeScript関係のパッケージは入っていません。
webpack.config.jsのmoduleの設定は以下の通りです。
module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'] } }, // その他ファイルについての記述は省略 ] },
BabelにてJSファイルをトランスパイルする設定が書かれています。古いブラウザでも動くように変換する@babel/preset-env
や、ReactのJSXを変換する@babel/preset-react
が設定されていています。
TypeScript関連パッケージインストール
npmでTypeScript関係のパッケージをインストールします。Reactで使用する型定義パッケージなども導入しています。
npm install --save-dev typescript @babel/preset-typescript \ @types/node \ @types/react \ @types/react-dom \ @types/jest
パッケージをインストールしたら、TypeScriptの設定ファイルであるtsconfig.jsonという設定ファイルを作成します。
{ "compilerOptions": { "target": "ES2015", "lib": ["dom", "dom.iterable", "esnext"], "module": "esnext", "jsx": "react-jsx", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "sourceMap": true, "allowJs": true }, "exclude": [ "node_modules" ] }
基本的には標準的な設定ですが、jsx
でreact-jsx
を指定することでReactのJSX構文に対応したり、allowJs
で通常のJavaScriptファイルもコンパイル対象に設定しています。
webpack設定変更
BabelでTypeScriptのトランスパイルを行うようにwebpack.config.jsの設定を変更します。
resolve: { extensions: ['.js', '.ts', '.tsx', '.json', '.css'] }, module: { rules: [ { test: /\.(js|ts|tsx)$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'] } }, // その他ファイルについての記述は省略 ] }
resolve.extensions
を指定することで、インポート時に拡張子を省略できるようにしています。
module
では、test
で.jsの他TypeScript関係の拡張子である.ts、.tsxもトランスパイル対象に含め、presets
にてBabelでTypeScriptをJavaSriptに変換するため@babel/preset-typescript
を設定しています。
既存コードのTS対応
これでTypeScriptをトランスパイルするための設定は完了したので、最後に既存の.jsファイルをTypeScript化していきます。
ただ、アプリの起動部分であるapp.js
ファイルについては、以下のようにJavaScriptコードのままにしています。ZAF(Zendesk Apps framework)等のZendeskアプリ開発に使用するSDKの型定義を用意するのが大変だからです。
import React from "react"; import { render } from "react-dom"; import { resizeContainer } from "../lib/helpers"; import { Container } from "./container"; const MAX_HEIGHT = 1000; class App { constructor(client, appData) { this._client = client; this._appData = appData; this.initializePromise = this.init(); } async init() { const container = document.querySelector(".main"); render(<Container client={this._client} />, container); return resizeContainer(this._client, MAX_HEIGHT); } } export default App;
上記のコードではContainerというReactコンポーネントがZAFクライアントが受け取っていますが、以下のように引数の型定義はanyで妥協しています。
export const Container: React.FC<{ client: any }> = ({ client }) => { // 中身は省略 }
ESLintとPrettierの導入
TypeScript開発に必ず必要なわけではありませんが、便利なのでESLintとPrettierも導入します。
npm install --save-dev eslint prettier eslint-config-prettier
ESLintの設定は以下のような形にし、Prettierと連携させています。
module.exports = { env: { browser: true, es2021: true, }, extends: ["plugin:react/recommended", "standard-with-typescript", "prettier"], overrides: [], parserOptions: { ecmaVersion: "latest", sourceType: "module", project: "./tsconfig.json", }, plugins: ["react"], rules: { "@typescript-eslint/explicit-function-return-type": "off", }, };
まとめ
ZCLIで生成したZendeskアプリ開発プロジェクトへTypeScriptを導入する手順をご紹介しました。アプリ開発は機能が複雑化しやすいため、型システムを活用して安全で読みやすいコードを書いていくのがオススメです。
なお、今回設定を行った実際のプロジェクトは、以下のGitHubリポジトリに保存してあります。リポジトリ名の通り、ZendeskとEメール配信サービスのSendGridを連携させてアプリを開発しています。